package com.lyn.io.file

import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory
import jxl.Workbook
import jxl.write.Label
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.FileReader
import java.io.FileWriter
import java.io.InputStream
import java.io.PrintStream

/**
 * 文件夹实现
 * @author longyn 2025/02/28
 * @version 1.0.0
 */
class FolderImp : Folder {

    private lateinit var path: String
    private lateinit var name: String
    private lateinit var rootPath: String
    private lateinit var rootFile: File

    override fun initialize(path: String, name: String,isCreate:Boolean): Boolean {
        try {
            this@FolderImp.path = path
            this@FolderImp.name = name
            if (isCreate){
                val file = File(path, name)
                if (!file.exists()) {
                    file.mkdirs()
                }
                this@FolderImp.rootPath = file.absolutePath
                this@FolderImp.rootFile = file
            }else{
                val file = File(path)
                this@FolderImp.rootPath = file.absolutePath
                this@FolderImp.rootFile = file
            }
            return true
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return false
    }


    override fun getName(): String {
        return this@FolderImp.name
    }

    override fun getRootPath(): String {
        return this@FolderImp.rootPath
    }

    override fun existFile(name: String): Boolean {
        val file = File(rootFile, name)
        return file.exists()
    }

    override fun getAllFileName(): MutableList<String> {
        val list = mutableListOf<String>()
        rootFile.listFiles()?.forEach {
            list.add(it.name)
        }
        return list
    }

    override fun createFolder(name: String): File {
        val file = File(rootFile, name)
        if (!file.exists()) {
            file.mkdirs()
        }
        return file
    }

    override fun createFile(name: String): File {
        val file = File(rootFile, name)
        if (!file.exists()) {
            file.createNewFile()
        }
        return file
    }

    override fun reName(oldName: String, newString: String):File? {
        val file = File(rootFile, oldName)
        if (file.exists()){
            val newFile = File(rootFile, newString)
            file.renameTo(newFile)
            return newFile
        }
        return null
    }

    override fun getFile(name: String): File {
        return File(rootFile, name)
    }

    override fun readFile(name: String): String {
        val file = File(rootFile, name)
        if (file.exists()) {
            val fileReader = FileReader(file)
            val s = fileReader.readText().trim()
            fileReader.close()
            return s
        }
        return ""
    }

    override fun writeFile(name: String, value: String, append: Boolean): String {
        val file = File(rootFile, name)
        if (!file.exists()) {
            file.createNewFile()
        }
        val fileWriter = FileWriter(file, append)
        fileWriter.write(value)
        fileWriter.flush()
        fileWriter.close()
        return file.absolutePath
    }

    override fun writeFile(file: File, name: String): String {
        return writeFile(file, name, true)
    }

    override fun writeFile(file: File, name: String, closeInputStream: Boolean): String {
        if (!file.exists()) {
            return ""
        }
        val fileInputStream = FileInputStream(file)
        return writeFile(fileInputStream, name, closeInputStream)
    }

    override fun writeFile(
        inputStream: InputStream,
        name: String,
        closeInputStream: Boolean
    ): String {
        try {
            val file = File(rootFile, name)
            if (!file.exists()) {
                file.createNewFile()
            }
            val fileOutputStream = FileOutputStream(file)
            val buff = ByteArray(1024)
            var len: Int
            while (inputStream.read(buff).apply { len = this } != -1) {
                fileOutputStream.write(buff, 0, len)
            }
            fileOutputStream.flush()
            fileOutputStream.close()
            if (closeInputStream) {
                inputStream.close()
            }
            return file.absolutePath
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return ""
    }

    override fun getFileInputStream(name: String): FileInputStream? {
        val file = File(rootFile, name)
        if (file.exists()) {
            return FileInputStream(file)
        }
        return null
    }

    override fun getFileOutPutStream(name: String): FileOutputStream? {
        val file = File(rootFile, name)
        if (file.exists()) {
            return FileOutputStream(file)
        }
        return null
    }

    override fun deleteFile(name: String) {
        val file = File(rootFile, name)
        deleteFile(file)
    }


    private fun deleteFile(file:File){
        if (file.exists()) {
            if (file.isFile){
                file.delete()
            }else{
                val listFiles = file.listFiles()
                if (listFiles != null){
                    for (f in listFiles){
                        deleteFile(f)
                    }
                }
                file.delete()
            }
        }
    }

    override fun updateFileName(oldName: String, newString: String): String {
        try {
            val file = File(rootFile, name)
            if (file.exists()) {
                val newFile = File(rootFile, newString)
                if (file.renameTo(newFile)) {
                    return newFile.absolutePath
                }
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return ""
    }

    override fun getBitmap(name: String): Bitmap? {
        try {
            val file = File(rootFile, name)
            if (file.exists()) {
                val fileInputStream = FileInputStream(file)
                val bitmap = BitmapFactory.decodeStream(fileInputStream)
                fileInputStream.close()
                return bitmap
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return null
    }

    override fun writeBitmap(
        name: String,
        bitmap: Bitmap,
        format: CompressFormat,
        quality: Int
    ): String {
        try {
            val file = File(rootFile, name)
            if (!file.exists()) {
                file.createNewFile()
            }
            val fileOutputStream = FileOutputStream(file)
            if (bitmap.compress(format, quality, fileOutputStream)) {
                fileOutputStream.flush()
                fileOutputStream.close()
                return file.absolutePath
            }
            fileOutputStream.flush()
            fileOutputStream.close()
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return ""
    }

    override fun <T> readXls(
        name: String,
        startRow: Int,
        endRow: Int,
        sheetPosition: Int,
        curClass: Class<T>
    ): MutableList<T> {
        val list: MutableList<T> = mutableListOf()
        try {
            val file = File(rootFile, name)
            if (!file.exists()) {
                return list
            }
            val workbook = Workbook.getWorkbook(file)
            val sheet = workbook.getSheet(sheetPosition)
            val columns = sheet.columns
            var rows = sheet.rows
            if (endRow > 0) {
                rows = endRow
            }
            for (r in startRow until rows) {
                val t = curClass.getDeclaredConstructor().newInstance()
                for (c in 0 until columns) {
                    val cell = sheet.getCell(c, r)
                    val contents = cell.contents
                    val fields = curClass::class.java.declaredFields
                    for (f in fields.indices) {
                        val field = fields[f]
                        field.isAccessible = true
                        val xlsColumn = field.getAnnotation(XlsColumn::class.java) ?: continue
                        if (xlsColumn.position == c) {
                            field.set(t, contents)
                        }
                    }
                }
                list.add(t)
            }
            return list
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return list
    }

    override fun <T> readXls(
        inputStream: InputStream,
        startRow: Int,
        endRow: Int,
        sheetPosition: Int,
        curClass: Class<T>
    ): MutableList<T> {
        val list: MutableList<T> = mutableListOf()
        try {
            val workbook = Workbook.getWorkbook(inputStream)
            val sheet = workbook.getSheet(sheetPosition)
            val columns = sheet.columns
            var rows = sheet.rows
            if (endRow > 0) {
                rows = endRow
            }
            for (r in startRow until rows) {
                val t = curClass.getDeclaredConstructor().newInstance()
                for (c in 0 until columns) {
                    val cell = sheet.getCell(c, r)
                    val contents = cell.contents
                    val fields = curClass::class.java.declaredFields
                    for (f in fields.indices) {
                        val field = fields[f]
                        field.isAccessible = true
                        val xlsColumn = field.getAnnotation(XlsColumn::class.java) ?: continue
                        if (xlsColumn.position == c) {
                            field.set(t, contents)
                        }
                    }
                }
                list.add(t)
            }
            return list
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return list
    }

    override fun <T> writeXls(
        name: String,
        writeTitle: Boolean,
        sheet: String,
        sheetPosition: Int,
        dataList: MutableList<T>,
        curClass: Class<T>
    ): String {
        val file = File(rootFile, name)
        if (!file.exists()) {
            file.createNewFile()
        }
        val workbook = Workbook.createWorkbook(file)
        val createSheet = workbook.createSheet(sheet, sheetPosition) ?: return file.absolutePath
        for (i in 0 until dataList.size) {
            val t = dataList[i]
            val fields = curClass.declaredFields
            for (f in fields.indices) {
                val field = fields[f]
                field.isAccessible = true
                val xlsColumn = field.getAnnotation(XlsColumn::class.java) ?: continue
                if (writeTitle) {
                    if (i == 0) {
                        try {
                            createSheet.addCell(Label(xlsColumn.position, i, xlsColumn.name))
                        } catch (e: Throwable) {
                            e.printStackTrace()
                        }
                        continue
                    }
                }
                try {
                    createSheet.addCell(Label(xlsColumn.position, i, field.get(t) as String))
                } catch (e: Throwable) {
                    e.printStackTrace()
                }
            }
        }
        try {
            workbook.write()
            workbook.close()
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return file.absolutePath
    }

    override fun getPrintStream(name: String): PrintStream? {
        try {
            val file = File(rootFile, name)
            if (!file.exists()) {
                file.createNewFile()
            }
            return PrintStream(name)
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return null
    }

    override fun writeStackTrace(name: String, throwable: Throwable): String {
        try {
            val file = File(rootFile, name)
            if (!file.exists()) {
                file.createNewFile()
            }
            val printStream = PrintStream(file.absolutePath)
            throwable.printStackTrace(printStream)
            return file.absolutePath
        } catch (e: Throwable) {
            e.printStackTrace()
        }
        return ""
    }
}